home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / mail / transpor / ifmail23.z / ifmail23 / ifmail / ifcico / zmrecv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-09  |  10.7 KB  |  556 lines

  1. #include <unistd.h>
  2. #include <time.h>
  3. #include <utime.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <limits.h>
  8. #include <fcntl.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #if defined(HAS_STATFS)
  12. #if defined(STATFS_IN_VFS_H)
  13. #include <sys/vfs.h>
  14. #elif defined(STATFS_IN_STATFS_H)
  15. #include <sys/statfs.h>
  16. #elif defined(STATFS_IN_STATVFS_H)
  17. #include <sys/statvfs.h>
  18. #elif defined(STATFS_IN_MOUNT_H)
  19. #include <sys/mount.h>
  20. #else
  21. #error No include for statfs() call defined
  22. #endif
  23. #elif defined(HAS_STATVFS)
  24. #include <sys/statvfs.h>
  25. #endif
  26. #include "xutil.h"
  27. #include "lutil.h"
  28. #include "ttyio.h"
  29. #include "zmodem.h"
  30. #include "session.h"
  31. #include "config.h"
  32. #include "emsi.h"
  33.  
  34. static FILE *fout=NULL;
  35.  
  36. static int Usevhdrs;
  37. static long rxbytes;
  38. static int Eofseen;        /* indicates cpm eof (^Z) has been received */
  39. static int errors;
  40. static time_t startime,etime;
  41. static long sbytes;
  42.  
  43. #define DEFBYTL 2000000000L    /* default rx file size */
  44. static long Bytesleft;        /* number of bytes of incoming file left */
  45. static long Modtime;        /* Unix style mod time for incoming file */
  46. static int Filemode;        /* Unix style mode for incoming file */
  47. #ifndef PATH_MAX
  48. #define PATH_MAX 512
  49. #endif
  50.  
  51. static int Thisbinary;        /* current file is to be received in bin mode */
  52.  
  53. static char *secbuf=0;
  54.  
  55. static int tryzhdrtype;
  56. static char zconv;        /* ZMODEM file conversion request */
  57. static char zmanag;        /* ZMODEM file management request */
  58. static char ztrans;        /* ZMODEM file transport request */
  59.  
  60. static int resync(off_t);
  61. static int tryz(void);
  62. static int rzfiles(void);
  63. static int rzfile(void);
  64. static void zmputs(char*);
  65. int closefile(int);
  66. int closeit(int);
  67. FILE *openfile(char*,time_t,off_t,off_t*,int(*)(off_t));
  68. static int putsec(char*,int);
  69. static int procheader(char*);
  70. static int ackbibi(void);
  71. #if defined(HAS_STATFS) | defined(HAS_STATVFS)
  72. static long getfree(void);
  73. #endif
  74.  
  75. void get_frame_buffer(void);
  76.  
  77. int zmrcvfiles(void);
  78. int zmrcvfiles(void)
  79. {
  80.     int rc;
  81.  
  82.     loginf("start %s receive",
  83.         (emsi_local_protos & ZAP)?"ZedZap":"Zmodem");
  84.  
  85.     get_frame_buffer();
  86.  
  87.     if (secbuf == NULL) secbuf=xmalloc(MAXBLOCK+1);
  88.     tryzhdrtype=ZRINIT;
  89.     if ((rc=tryz()) < 0)
  90.     {
  91.         loginf("zmrecv could not initiate receive, rc=%d",rc);
  92.     }
  93.     else switch (rc)
  94.     {
  95.     case ZCOMPL:    rc=0; break;
  96.     case ZFILE:    rc=rzfiles(); break;
  97.     }
  98.     if (fout)
  99.     { 
  100.         if (closeit(0)) {
  101.             logerr("Error closing file");
  102.         }
  103.     }    
  104.     loginf("zmodem receive rc=%d",rc);
  105.     return abs(rc);
  106. }
  107.  
  108. /*
  109.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  110.  *  Handles ZSINIT frame
  111.  *  Return ZFILE if Zmodem filename received, -1 on error,
  112.  *   ZCOMPL if transaction finished,  else 0
  113.  */
  114. int tryz(void)
  115. {
  116.     register c, n, numfin=0;
  117.     register cmdzack1flg;
  118.  
  119.     debug(11,"tryz");
  120.     for (n=15; --n>=0; ) {
  121.         /* Set buffer length (0) and capability flags */
  122.         stohdr(0L);
  123.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  124.         if (Zctlesc)
  125.             Txhdr[ZF0] |= TESCCTL;
  126.         Txhdr[ZF0] |= CANRLE;
  127.         Txhdr[ZF1] = CANVHDR;
  128.         zshhdr(4,tryzhdrtype, Txhdr);
  129.         if (tryzhdrtype == ZSKIP)       /* Don't skip too far */
  130.             tryzhdrtype = ZRINIT;   /* CAF 8-21-87 */
  131.  
  132. again:
  133.         switch (zgethdr(Rxhdr, 0)) {
  134.         case ZRQINIT:
  135.             if (Rxhdr[ZF3] & 0x80)
  136.                 Usevhdrs = 1;    /* we can var header */
  137.             continue;
  138.         case ZEOF:
  139.             continue;
  140.         case TIMEOUT:
  141.             if (numfin > 0) return ackbibi();
  142.             else continue;
  143.         case ZFILE:
  144.             zconv = Rxhdr[ZF0];
  145.             zmanag = Rxhdr[ZF1];
  146.             ztrans = Rxhdr[ZF2];
  147.             if (Rxhdr[ZF3] & ZCANVHDR)
  148.                 Usevhdrs = TRUE;
  149.             tryzhdrtype = ZRINIT;
  150.             c = zrdata(secbuf, MAXBLOCK);
  151.             if (c == GOTCRCW)
  152.                 return ZFILE;
  153.             zshhdr(4,ZNAK, Txhdr);
  154.             goto again;
  155.         case ZSINIT:
  156.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  157.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  158.                 stohdr(1L);
  159.                 zshhdr(4,ZACK, Txhdr);
  160.                 goto again;
  161.             }
  162.             zshhdr(4,ZNAK, Txhdr);
  163.             goto again;
  164.         case ZFREECNT:
  165.             stohdr(getfree());
  166.             zshhdr(4,ZACK, Txhdr);
  167.             goto again;
  168.         case ZCOMMAND:
  169.             cmdzack1flg = Rxhdr[ZF0];
  170.             if (zrdata(secbuf, MAXBLOCK) == GOTCRCW) {
  171.                 if (cmdzack1flg & ZCACK1)
  172.                     stohdr(0L);
  173.                 else
  174.                     loginf("request for command \"%s\" ignored",
  175.                         printable(secbuf,-32));
  176.                     stohdr(0L);
  177.                 do {
  178.                     zshhdr(4,ZCOMPL, Txhdr);
  179.                 }
  180.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  181.                 return ackbibi();
  182.             }
  183.             zshhdr(4,ZNAK, Txhdr); goto again;
  184.         case ZCOMPL:
  185.             goto again;
  186.         case ZRINIT:
  187.         case ZFIN: /* do not beleive in first ZFIN */
  188.             if (numfin++ > 0) return ackbibi();
  189.             else continue;
  190.         case ERROR:
  191.         case HANGUP:
  192.         case ZCAN:
  193.             return ERROR;
  194.         default:
  195.             continue;
  196.         }
  197.     }
  198.     return 0;
  199. }
  200.  
  201. /*
  202.  * Receive 1 or more files with ZMODEM protocol
  203.  */
  204. int rzfiles(void)
  205. {
  206.     register c;
  207.  
  208.     debug(11,"rzfiles");
  209.     for (;;) {
  210.         switch (c = rzfile()) {
  211.         case ZEOF:
  212.         case ZSKIP:
  213.             switch (tryz()) {
  214.             case ZCOMPL:
  215.                 return OK;
  216.             default:
  217.                 return ERROR;
  218.             case ZFILE:
  219.                 break;
  220.             }
  221.             continue;
  222.         default:
  223.             return c;
  224.         case ERROR:
  225.             return ERROR;
  226.         }
  227.     }
  228. }
  229.  
  230. /*
  231.  * Receive a file with ZMODEM protocol
  232.  *  Assumes file name frame is in secbuf
  233.  */
  234. int rzfile(void)
  235. {
  236.     register c, n;
  237.  
  238.     debug(11,"rzfile");
  239.     Eofseen=FALSE;
  240.     rxbytes = 0l;
  241.     if ((c = procheader(secbuf))) {
  242.         return (tryzhdrtype = c);
  243.     }
  244.  
  245.     n = 20;
  246.  
  247.     for (;;) {
  248.         stohdr(rxbytes);
  249.         zshhdr(4,ZRPOS, Txhdr);
  250. nxthdr:
  251.         switch (c = zgethdr(Rxhdr, 0)) {
  252.         default:
  253.             debug(11,"rzfile: Wrong header %d", c);
  254.             if ( --n < 0) {
  255.                 loginf("Wrong header %d", c);
  256.                 return ERROR;
  257.             }
  258.             continue;
  259.         case ZCAN:
  260.             loginf("Sender CANcelled");
  261.             return ERROR;
  262.         case ZNAK:
  263.             if ( --n < 0) {
  264.                 loginf("got ZNAK", c);
  265.                 return ERROR;
  266.             }
  267.             continue;
  268.         case TIMEOUT:
  269.             if ( --n < 0) {
  270.                 loginf("TIMEOUT", c);
  271.                 return ERROR;
  272.             }
  273.             continue;
  274.         case ZFILE:
  275.             zrdata(secbuf, MAXBLOCK);
  276.             continue;
  277.         case ZEOF:
  278.             if (rclhdr(Rxhdr) != rxbytes) {
  279.                 /*
  280.                  * Ignore eof if it's at wrong place - force
  281.                  *  a timeout because the eof might have gone
  282.                  *  out before we sent our zrpos.
  283.                  */
  284.                 errors = 0;  goto nxthdr;
  285.             }
  286.             if (closeit(1)) {
  287.                 tryzhdrtype = ZFERR;
  288.                 logerr("Error closing file");
  289.                 return ERROR;
  290.             }
  291.             fout=NULL;
  292.             debug(11,"rzfile: normal EOF");
  293.             return c;
  294.         case HANGUP:
  295.             loginf("Line drop");
  296.             return ERROR;
  297.         case ERROR:    /* Too much garbage in header search error */
  298.             if (--n < 0) {
  299.                 loginf("Too much errors");
  300.                 return ERROR;
  301.             }
  302.             zmputs(Attn);
  303.             continue;
  304.         case ZSKIP:
  305.             Modtime = 1;
  306.             closeit(1);
  307.             loginf("Sender SKIPPED file");
  308.             return c;
  309.         case ZDATA:
  310.             if (rclhdr(Rxhdr) != rxbytes) {
  311.                 if ( --n < 0) {
  312.                     loginf("Data has bad addr");
  313.                     return ERROR;
  314.                 }
  315.                 zmputs(Attn);  continue;
  316.             }
  317. moredata:
  318.                 debug(11,"%7ld ZMODEM%s    ",
  319.                   rxbytes, Crc32r?" CRC-32":"");
  320.             switch (c = zrdata(secbuf, MAXBLOCK))
  321.             {
  322.             case ZCAN:
  323.                 loginf("Sender CANcelled");
  324.                 return ERROR;
  325.             case HANGUP:
  326.                 loginf("Line drop");
  327.                 return ERROR;
  328.             case ERROR:    /* CRC error */
  329.                 if (--n < 0) {
  330.                     loginf("Too many errors");
  331.                     return ERROR;
  332.                 }
  333.                 zmputs(Attn);
  334.                 continue;
  335.             case TIMEOUT:
  336.                 if ( --n < 0) {
  337.                     loginf("TIMEOUT");
  338.                     return ERROR;
  339.                 }
  340.                 continue;
  341.             case GOTCRCW:
  342.                 n = 20;
  343.                 putsec(secbuf, Rxcount);
  344.                 rxbytes += Rxcount;
  345.                 stohdr(rxbytes);
  346.                 zshhdr(4,ZACK, Txhdr);
  347.                 PUTCHAR(DC1);
  348.                 goto nxthdr;
  349.             case GOTCRCQ:
  350.                 n = 20;
  351.                 putsec(secbuf, Rxcount);
  352.                 rxbytes += Rxcount;
  353.                 stohdr(rxbytes);
  354.                 zshhdr(4,ZACK, Txhdr);
  355.                 goto moredata;
  356.             case GOTCRCG:
  357.                 n = 20;
  358.                 putsec(secbuf, Rxcount);
  359.                 rxbytes += Rxcount;
  360.                 goto moredata;
  361.             case GOTCRCE:
  362.                 n = 20;
  363.                 putsec(secbuf, Rxcount);
  364.                 rxbytes += Rxcount;
  365.                 goto nxthdr;
  366.             }
  367.         }
  368.     }
  369. }
  370.  
  371. /*
  372.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  373.  *   and \335 (break signal)
  374.  */
  375. void zmputs(s)
  376. char *s;
  377. {
  378.     register c;
  379.  
  380.     debug(11,"zmputs");
  381.     while (*s) {
  382.         switch (c = *s++) {
  383.         case '\336':
  384.             sleep(1); continue;
  385.         case '\335':
  386.             sendbrk(); continue;
  387.         default:
  388.             PUTCHAR(c);
  389.         }
  390.     }
  391. }
  392.  
  393. int resync(off)
  394. off_t off;
  395. {
  396.     return 0;
  397. }
  398.  
  399. int closeit(success)
  400. int success;
  401. {
  402.     int rc;
  403.  
  404.     rc=closefile(success);
  405.     fout=NULL;
  406.     sbytes=rxbytes-sbytes;
  407.     (void)time(&etime);
  408.     if ((startime=etime-startime) == 0L) startime=1L;
  409.     loginf("%s %lu bytes in %ld seconds (%ld cps)",
  410.         success?"received":"dropped after",
  411.         sbytes,startime,sbytes/startime);
  412.     return rc;
  413. }
  414.  
  415. /*
  416.  * Ack a ZFIN packet, let byegones be byegones
  417.  */
  418. int ackbibi(void)
  419. {
  420.     register n;
  421.     int c;
  422.  
  423.     debug(11,"ackbibi:");
  424.     stohdr(0L);
  425.     for (n=3; --n>=0; ) {
  426.         zshhdr(4,ZFIN, Txhdr);
  427.         switch ((c=GETCHAR(10))) {
  428.         case ZPAD:
  429.             zgethdr(Rxhdr,0);
  430.             debug(11,"skipped unexpected header");
  431.             break;
  432.         case 'O':
  433.             GETCHAR(1);    /* Discard 2nd 'O' */
  434.             debug(11,"ackbibi complete");
  435.             return ZCOMPL;
  436.         case ERROR:
  437.         case HANGUP:
  438.             debug(11,"ackbibi got %d, ignore",c);
  439.             return 0;
  440.         case TIMEOUT:
  441.         default:
  442.             debug(11,"ackbibi got '%s', continue",
  443.                 printablec(c));
  444.             break;
  445.         }
  446.     }
  447.     return ZCOMPL;
  448. }
  449.  
  450. /*
  451.  * Process incoming file information header
  452.  */
  453. int procheader(name)
  454. char *name;
  455. {
  456.     register char *openmode, *p;
  457.     static dummy;
  458.     char ctt[32];
  459.  
  460.     debug(11,"proheader \"%s\"",printable(name,0));
  461.     /* set default parameters and overrides */
  462.     openmode = "w";
  463.  
  464.     /*
  465.      *  Process ZMODEM remote file management requests
  466.      */
  467.     Thisbinary = (zconv != ZCNL);    /* Remote ASCII override */
  468.     if (zmanag == ZMAPND)
  469.         openmode = "a";
  470.  
  471.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  472.  
  473.     p = name + 1 + strlen(name);
  474.     sscanf(p, "%ld%lo%o%lo%d%ld%d%d",
  475.       &Bytesleft, &Modtime, &Filemode,
  476.       &dummy, &dummy, &dummy, &dummy, &dummy);
  477.     strcpy(ctt,date(Modtime));
  478.     loginf("zmodem receive: \"%s\" %ld bytes dated %s mode %o",
  479.       name, Bytesleft, ctt, Filemode);
  480.  
  481.     fout=openfile(name,Modtime,Bytesleft,&rxbytes,resync);
  482.     (void)time(&startime);
  483.     sbytes=rxbytes;
  484.  
  485.     if (Bytesleft == rxbytes) {
  486.         loginf("Skipping %s", name);
  487.         closeit(0);
  488.         return ZSKIP;
  489.     }
  490.     else if ( !fout) return ZFERR;
  491.     else return 0;
  492. }
  493.  
  494. /*
  495.  * Putsec writes the n characters of buf to receive file fout.
  496.  *  If not in binary mode, carriage returns, and all characters
  497.  *  starting with CPMEOF are discarded.
  498.  */
  499. int putsec(buf, n)
  500. char *buf;
  501. register n;
  502. {
  503.     register char *p;
  504.  
  505.     debug(11,"putsec %d bytes",n);
  506.     if (n == 0)
  507.         return OK;
  508.     if (Thisbinary) {
  509.         for (p=buf; --n>=0; )
  510.             putc( *p++, fout);
  511.     }
  512.     else {
  513.         if (Eofseen)
  514.             return OK;
  515.         for (p=buf; --n>=0; ++p ) {
  516.             if ( *p == '\r')
  517.                 continue;
  518.             if (*p == SUB) {
  519.                 Eofseen=TRUE; return OK;
  520.             }
  521.             putc(*p ,fout);
  522.         }
  523.     }
  524.     return OK;
  525. }
  526.  
  527. #if defined(HAS_STATFS) || defined(HAS_STATVFS)
  528. long getfree(void)
  529. {
  530. #ifdef HAS_STATVFS
  531.     struct statvfs sfs;
  532.  
  533.     if (statvfs(inbound,&sfs) != 0)
  534. #else
  535.     struct statfs sfs;
  536.  
  537. #ifdef SCO_STYLE_STATFS
  538.     if (statfs(inbound,&sfs,sizeof(sfs),0) != 0)
  539. #else
  540.     if (statfs(inbound,&sfs) != 0)
  541. #endif
  542. #endif
  543.     {
  544.         logerr("$cannot statfs \"%s\", assume enough space",
  545.             inbound);
  546.         return -1L;
  547.     }
  548.     else return (sfs.f_bsize*sfs.f_bfree);
  549. }
  550. #else
  551. long getfree(void)
  552. {
  553.     return MAXLONG;
  554. }
  555. #endif /* defined(HAS_STATFS) | defined(HAS_STATVFS) */
  556.